package security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import security.config.handler.*;
import security.filter.TokenAuthFilter;
import security.filter.TokenLoginFilter;
import security.service.UserDetailService;

/**
 * security 配置类
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 方法增加权限
public class MyTokenSecurityConfig extends WebSecurityConfigurerAdapter {

    // 将 UserDetailService 注入，使其去查询数据库
    @Autowired
    private UserDetailService userDetailsService;

    // token 生成器
    @Autowired
    private TokenJwtManager tokenManager;

    // 自定义密码加密解密
    @Autowired
    private DefaultPwdEndoder defaultPwdEndoder;

    // 未登录handler
    @Autowired
    private MyUnAuthEntryPoint myUnAuthEntryPoint;

    // 无权限
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    //  登出handler处理
    @Autowired
    private MyLogoutHandler myLogoutHandler;

    // 登录失败
    @Autowired
    private LoginFailedHandler loginFailedHandler;

    // 登录成功
    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    /**
     * 登录时，从数据库获取基本信息和权限信息
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置 userDetailsService 和 密码解析
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPwdEndoder);
    }

    /**
     * 配置访问过滤
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(myUnAuthEntryPoint) // 未登录 handler
                .accessDeniedHandler(myAccessDeniedHandler) // 无权限

                .and().csrf().disable() // 关闭 csrf 跨域请求

                .formLogin()
                .loginProcessingUrl("/user/login")  // 设定登录请求接口
                .usernameParameter("userName")
                .passwordParameter("passWord")
                //.successHandler(loginSuccessHandler) // 因为有了 TokenLoginFilter 配置过滤器，此处配置没用
                //.failureHandler(loginFailedHandler) // 因为有了 TokenLoginFilter 配置过滤器，此处配置没用
                .permitAll() // 允许所有用户访问

                .and()
                .authorizeRequests() // 请求设置
                .antMatchers("/test").permitAll() // 配置不需要认证的接口
                .anyRequest().authenticated() // 任何请求都需要认证


                .and()
                .logout() // logout设定
                .logoutUrl("/logouts")  //退出请求  /logouts 未定义，交给自定义handler实现功能
                .addLogoutHandler(myLogoutHandler) // 登出 myLogoutHandler 处理

                .and()
                .addFilter(new TokenLoginFilter(tokenManager,authenticationManager())) // 认证交给 自定义 TokenLoginFilter 实现
                .addFilter(new TokenAuthFilter(authenticationManager(),tokenManager))

                // basic 方式 ，参考资料：https://www.cnblogs.com/xiaoxiaotank/p/11009796.html
                .httpBasic();

    }

    /**
     * 配置不需要验证的访问路径
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //web.ignoring().antMatchers("/test","/user/login");
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}
